#include "mem_pool.h"
#define LOG_SET_LOCAL_LEVEL LOG_LEVEL_NONE
#include "log.h"

static float32_t origArray[MEM_POOL_CAPACITY * SEGMENT_CAPACITY];
static segment_t segArray[MEM_POOL_CAPACITY];
static mem_pool_t mem_pool;

__STATIC_INLINE void mem_pool_move_one(segment_t *srcPtr, segment_t *dstPtr) {
    
    uint8_t *srcHeadPtr = (uint8_t *)srcPtr->DataPtr;
    uint8_t *dstHeadPtr = (uint8_t *)dstPtr->DataPtr;
    uint32_t segLen = sizeof(*srcPtr->DataPtr) * srcPtr->Len;
    
    for(uint32_t i = 0U; i < segLen; i++) {
        dstHeadPtr[i] = srcHeadPtr[i];
    } 
}

__STATIC_INLINE segment_t* mem_pool_re_req(segment_t *segPtr) {
    
    assert_param(segPtr != NULL);

    if (segPtr->IsUsed == false) {
        mem_pool.Used++;
        segPtr->IsUsed = true;
    }
    LOG_debug("Mem rerequest segment(%d) pool->Len: %d", segPtr->No, mem_pool.Used);
    return segPtr;
}


mem_pool_t* mem_pool_init() {
    
    for (uint32_t i = 0U; i < MEM_POOL_CAPACITY; i ++) {
        segment_init(segArray + i, origArray + i * SEGMENT_CAPACITY, i);
    }
    mem_pool.Unuse = segArray;
    mem_pool.Used = 0U;
    mem_pool.Capacity = MEM_POOL_CAPACITY;
    return &mem_pool;
}

segment_t* mem_pool_req() {
    
    assert_param(mem_pool.Used <= mem_pool.Capacity);

    segment_t *segPtr = mem_pool.Unuse;
    segPtr->IsUsed = true;
    do {
        mem_pool.Unuse++;
    }while (mem_pool.Unuse->IsUsed == true);
    mem_pool.Used++;
    LOG_debug("Mem requst segment(%d) pool->Len: %d", segPtr->No, mem_pool.Used);
    return segPtr;
}

void mem_pool_rel(segment_t *segPtr) {
    
    assert_param(segPtr != NULL);
    
    if (segPtr->No < mem_pool.Unuse->No) {
        mem_pool.Unuse = segPtr;
    }
    if (segPtr->IsUsed == true) {
        segPtr->IsUsed = false;
        mem_pool.Used--;
        LOG_debug("Mem release segment(%d) pool->Len: %d", segPtr->No, mem_pool.Used);
    }
}

void mem_pool_move(segment_t *srcPtr, segment_t *dstPtr, uint32_t len) {
    
    assert_param(srcPtr != NULL);
    assert_param(dstPtr != NULL);
    
    for(uint32_t i = 0U; i < len; i++) {
        mem_pool_rel(srcPtr + i);
        mem_pool_move_one(srcPtr + i, mem_pool_re_req(dstPtr + i));
    }
    mem_pool.Unuse = segArray;
    do {
        mem_pool.Unuse++;
    }while (mem_pool.Unuse->IsUsed == true);
    LOG_debug("Fix unuse pointer to segment(%d)", mem_pool.Unuse->No);
}
